<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="KBUGa" id="KBUGa"><span data-lake-id="u1cdd4b95" id="u1cdd4b95">典型回答</span></h1>
  <p data-lake-id="u7fc976d7" id="u7fc976d7"><br></p>
  <p data-lake-id="ub40164bd" id="ub40164bd"><span data-lake-id="u5bca4d5d" id="u5bca4d5d">字符串常量池（String Constant Pool）是Java中一块特殊的内存区域，用于存储字符串常量。</span></p>
  <p data-lake-id="ue25b3fc4" id="ue25b3fc4"><span data-lake-id="u6d2b7390" id="u6d2b7390">​</span><br></p>
  <p data-lake-id="u79da7cdc" id="u79da7cdc"><span data-lake-id="u4fe20caa" id="u4fe20caa">当程序中出现字符串常量时，Java编译器会将其放入字符串常量池中。字符串常量是不可变的，因此可以共享。如果字符串常量池中已存在相同内容的字符串，编译器会直接引用已存在的字符串常量，而不会创建新的对象。</span></p>
  <p data-lake-id="u600e7e90" id="u600e7e90"><span data-lake-id="u8c07d439" id="u8c07d439">​</span><br></p>
  <p data-lake-id="uf56dd914" id="uf56dd914"><span data-lake-id="u6713d422" id="u6713d422">在HotSpot虚拟机中：</span></p>
  <p data-lake-id="ucc0bc80e" id="ucc0bc80e"><br></p>
  <p data-lake-id="ubb8fb380" id="ubb8fb380"><span data-lake-id="u446c8b71" id="u446c8b71">在JDK 1.6及之前的版本，字符串常量池通常被实现为方法区的一部分，即永久代（Permanent Generation），用于存储类信息、常量池、静态变量、即时编译器编译后的代码等数据。</span></p>
  <p data-lake-id="ud2ba9ab0" id="ud2ba9ab0"><span data-lake-id="u1fb4df5b" id="u1fb4df5b">​</span><br></p>
  <p data-lake-id="u6231b4c8" id="u6231b4c8"><span data-lake-id="u7f498f0b" id="u7f498f0b">从JDK 1.7开始，字符串常量池的实现方式发生了重大改变。字符串常量池不再位于永久代，而是直接存放在堆（Heap）中，与其他对象共享堆内存。</span></p>
  <p data-lake-id="u8a7bfa21" id="u8a7bfa21"><span data-lake-id="u53f14b8d" id="u53f14b8d">​</span><br></p>
  <p data-lake-id="ue23c1821" id="ue23c1821"><span data-lake-id="u0b54240c" id="u0b54240c">之所以要挪到堆内存中，主要原因是因为永久代的 GC 回收效率太低，只有在FullGC的时候才会被执行回收。但是Java中往往会有很多字符串也是朝生夕死的，将字符串常量池放到堆中，能够更高效及时地回收字符串内存</span></p>
  <h1 data-lake-id="xKebQ" id="xKebQ"><span data-lake-id="u59d8d772" id="u59d8d772">扩展知识</span></h1>
  <p data-lake-id="u601f1c85" id="u601f1c85"><br></p>
  <h2 data-lake-id="p6Q1j" id="p6Q1j"><span data-lake-id="u2da0de74" id="u2da0de74">字符串常量从哪来的？</span></h2>
  <p data-lake-id="u9778e274" id="u9778e274"><br></p>
  <p data-lake-id="ubfccd0f8" id="ubfccd0f8"><span data-lake-id="u21f4c4c5" id="u21f4c4c5">字符串常量池中的常量有以下几个来源：</span></p>
  <p data-lake-id="ub7fe03dd" id="ub7fe03dd"><span data-lake-id="uc5683b96" id="uc5683b96">​</span><br></p>
  <p data-lake-id="ub21fb4cd" id="ub21fb4cd"><span data-lake-id="ua4942c90" id="ua4942c90">1、字面量常量。</span></p>
  <p data-lake-id="ud7b704f6" id="ud7b704f6"><span data-lake-id="uc6d3adc2" id="uc6d3adc2">​</span><br></p>
  <p data-lake-id="uf02fb856" id="uf02fb856"><span data-lake-id="u313cf37d" id="u313cf37d">在代码中直接使用双引号括起来的字符串字面值（如</span><code data-lake-id="u2ba30139" id="u2ba30139"><span data-lake-id="u359eb7cc" id="u359eb7cc">String s = "Hollis"</span></code><span data-lake-id="u25740e33" id="u25740e33">）会被认为是常量，并且会在编译后进入class文件的常量池，并且在运行阶段，进入字符串常量池。这是最常见的字符串常量来源。</span></p>
  <p data-lake-id="u0556eb0b" id="u0556eb0b"><span data-lake-id="u99047494" id="u99047494">​</span><br></p>
  <p data-lake-id="u956790eb" id="u956790eb"><span data-lake-id="uda5b4b1e" id="uda5b4b1e">2、intern()方法</span></p>
  <p data-lake-id="u4f183501" id="u4f183501"><span data-lake-id="ud7bc208b" id="ud7bc208b">​</span><br></p>
  <p data-lake-id="ua812d1ac" id="ua812d1ac"><span data-lake-id="ufa08a32c" id="ufa08a32c">String类提供了一个intern()方法，用于将字符串对象手动添加到字符串常量池中。调用intern()方法时，如果字符串常量池中已经存在相同内容的字符串，将会返回常量池中的引用；如果不存在，则会在常量池中创建新的字符串</span></p>
  <p data-lake-id="ubd9d4225" id="ubd9d4225"><br></p>
 </body>
</html>